package com.gzhryc.socket.netty;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import com.gzhryc.common.logging.Logger;
import com.gzhryc.socket.SocketCallback;
import com.gzhryc.socket.SocketEvent;
import com.gzhryc.socket.SocketMessage;
import com.gzhryc.socket.SocketNode;
import com.gzhryc.socket.message.TextWebSocketMessage;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
	
	static Logger log = Logger.getLogger(WebSocketServerHandler.class);
    
	final SocketNode mNode;
	final SocketCallback mCallback;
	
	WebSocketServerHandshaker handshaker;
	
	public WebSocketServerHandler(SocketNode mNode, SocketCallback callback) {
		this.mNode = mNode;
		this.mCallback = callback;
	}
	
	@Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
		log.info("msg type = {{0}}", msg);
        if (msg instanceof FullHttpRequest) {
            handleHttpRequest(ctx, (FullHttpRequest) msg);
        }else if (msg instanceof WebSocketFrame) {
            handleWebSocketFrame(ctx, (WebSocketFrame) msg);
        }
    }
 
    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
    	final Channel channel = ctx.channel();
		mNode.runTask(new Runnable() {
			public void run() {
				WebSocketServerHandshakerFactory handshakerFactory = new WebSocketServerHandshakerFactory("ws://127.0.0.1:10083/ws",null,false);
				handshaker = handshakerFactory.newHandshaker(req);
				if(handshaker != null) {
					handshaker.handshake(channel, req);
					
					SocketEvent event = new SocketEvent(new ChannelSocketNode(channel));
					mCallback.connected(event);
					
				}else {
					WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(channel);
				}
			}
		});
    }
 
    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
    	try {
    		if (frame instanceof TextWebSocketFrame) {
    			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    	    	frame.content().readBytes(outputStream,frame.content().readableBytes());
    	    	final SocketMessage byteMsg = new TextWebSocketMessage(outputStream.toByteArray());
    			final Channel channel = ctx.channel();
    			mNode.runTask(new Runnable() {
    				public void run() {
    					SocketEvent event = new SocketEvent(new ChannelSocketNode(channel),byteMsg);
    					mCallback.messageArrived(event);
    				}
    			});
            } else if (frame instanceof PingWebSocketFrame) {
                // 对于Ping消息，直接返回Pong消息
                ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            } else if (frame instanceof CloseWebSocketFrame) {
                // 对于关闭连接的消息，关闭channel
            	if(handshaker != null) {
            		handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            	}
            }
    	}catch(IOException e) {
    		log.error(e.getMessage(), e);
    	}
    }

}
